/*
 * Copyright 2008 Carnegie Mellon University
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, 
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package edu.cmu.lti.sepia.servlet;

import java.io.IOException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.FileUtils;

import edu.cmu.lti.sepia.data.db.FilePermissisonDAO;
import edu.cmu.lti.sepia.data.db.SQL;
import edu.cmu.lti.sepia.data.db.TaskDAO;
import edu.cmu.lti.sepia.data.db.UploadedFileDAO;
import edu.cmu.lti.sepia.data.db.UserDAO;
import edu.cmu.lti.sepia.infra.system.model.FilePermission;
import edu.cmu.lti.sepia.infra.system.model.UploadedFile;
import edu.cmu.lti.sepia.infra.system.model.User;
import edu.cmu.lti.sepia.infra.topic.model.Task;
import edu.cmu.lti.sepia.util.Logger;
import edu.cmu.lti.sepia.util.ServletUtil;

public class FileManager extends Uploader {

  private static final long serialVersionUID = 1L;
  private final static String UPDATE_SUCCEEDED = "<strong style=\"color:#ff0000;\">Update succeeded.</strong>\n";
  private final static String DELETE_SUCCEEDED = "<strong style=\"color:#ff0000;\">Delete succeeded.</strong>\n";
  
  public void doPost(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, IOException {
    StringBuilder report = new StringBuilder();
    String[] fileIds = request.getParameterValues("fileId");
    String action = request.getParameter("actionType");
    String filetype = ""; // if upload, this field will be fill in
    SQL sql = new SQL();
    try {
      if (action==null) { // upload. actionType cannot be obtained when form enctype is multipart/form-data
        ServletUtil s = new ServletUtil( request );
        int userId = s.readInt("userId", -1);
        int taskId = s.readInt("taskId", -1);
        UploadResult result = upload(request, response, sql, userId, taskId);
        filetype = result.params.get("filetype");
        report.append("Uploading \""+result.params.get("filename")+"\"...<br>\n");
        report.append(result.report);
      } else if (action.equals("download")) {
        String URL = "/io/file_fetcher.html";
        RequestDispatcher rd = getServletContext().getRequestDispatcher(URL);
        rd.forward(request,response); 
      } else if (action.equals("update")) {
        //fileId to list of taskIds
        Map<Integer,FilePermission> permissions = new HashMap<Integer,FilePermission>(fileIds.length);
        //fileId to userId
        Map<Integer,Integer> fileOwnerMap = new HashMap<Integer,Integer>(fileIds.length);
       
        Enumeration<?> e = request.getParameterNames();
        while (e.hasMoreElements()) {
          String key = (String) e.nextElement();
          if (key.startsWith("permission")) {
            String[] items = key.split("-");
            int fileId = Integer.parseInt(items[1]);
            int taskId = Integer.parseInt(items[2]);
            FilePermission fp = permissions.get(fileId);
            if (fp==null) {
              fp = new FilePermission(fileId);
            }
            fp.add(taskId);
            permissions.put(fileId, fp);
          } else if (key.startsWith("owner")) {
            String[] items = key.split("-");
            int fileId = Integer.parseInt(items[1]);
            Object a = request.getParameter(key);
            int userId = Integer.parseInt(a.toString());
            fileOwnerMap.put(fileId, userId);
          }
        }
        
        for ( String fileIdStr : fileIds ) {
          int fileId = Integer.parseInt(fileIdStr);
          int userId = fileOwnerMap.get(fileId);
          FilePermission fp = permissions.get(fileId);
          
          UploadedFileDAO.updateUser(sql, fileId, userId);
          FilePermissisonDAO.updateFilePermissison(sql, fileId, fp);
        }
        Logger.log( sql, request.getSession(), "UPDATE FILE", "fileIds="+Arrays.toString(fileIds) );
        report.append(UPDATE_SUCCEEDED+" Affected "+fileIds.length+" rows.<br>");
      } else if (action.equals("delete")) {
        for ( String fileIdStr : fileIds ) {
          int fileId = Integer.parseInt(fileIdStr);
          UploadedFileDAO.deleteFile(sql, fileId);
        }
        Logger.log( sql, request.getSession(), "DELETE FILE", "fileIds="+Arrays.toString(fileIds) );
        report.append(DELETE_SUCCEEDED+" Affected "+fileIds.length+" rows.<br>");
      }
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      try {
        sql.close(); 
      } catch (Exception e) {}
    }
    
    Commons.printHeader(request, response, "File Manager", 1);
    response.getOutputStream().println(
            "<div style=\"border:2px solid #ff0000;padding:10px\">" +
            "<h4>Result of action</h4><br>\n"+report.toString()+"</div>\n");
    printMain(request, response, filetype);
    Commons.printFooter(request, response);
  }
  
  public void doGet(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, IOException {
    Commons.printHeader(request, response, "File Manager", 1);
    printMain(request, response, "");
    Commons.printFooter(request, response);
  }

  public void printMain(HttpServletRequest request, HttpServletResponse response, String filetype)
  throws ServletException, IOException {
    StringBuilder sb = new StringBuilder();
    SQL sql = new SQL();

    try {
      List<User> users = UserDAO.getUsers(sql);
      List<Task> tasks = TaskDAO.getTasks(sql);
      List<UploadedFile> files = UploadedFileDAO.getFiles(sql);
      sb.append( getUploadForm(request, response, request.getRequestURI(), filetype) );
      sb.append("<br><hr><br>\n");
      if (files.size()>0) {
        sb.append("<h4>Downloader / Permission Manager </h4><br>\n");      
        sb.append("The table below contains all files uploaded to SEPIA in the order of date uploaded.<br> \n"); 
        sb.append("Select files and choose actions from one of \"Download\" \"Update Owner/Visibility\" and \"Delete\".<br> \n"); 
        sb.append("Each file is downloadable to its file owner (by default, the one uploaded the file) and participants in the task specified by \"Visibility to Task Participants\".\n");
        sb.append("<form action=\""+request.getRequestURL()+"\" method=\"POST\" name=\"dl_form\">");
        sb.append("<table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" class=\"datatable\">\n");
        sb.append("<thead>"+getTableHeader(tasks)+"</thead>\n");
        sb.append("<tbody>\n");
        sb.append( listMySubmission( files, users, tasks ) );
        sb.append("</tbody>\n");
        sb.append("</table>\n");
        sb.append(getButton());
        sb.append("</form>\n");
      } else {
        sb.append("<strong>No files are uploaded yet.</strong>");
      }
    } catch (Exception e) {
      throw new IOException(e);
    } finally {
      try {
        sql.close();
      } catch (Exception e){e.printStackTrace();}
    }

    response.getOutputStream().println(sb.toString());
  }
  
  public String listMySubmission(List<UploadedFile> files, List<User> users, List<Task> tasks) 
  throws Exception {

    StringBuilder sb = new StringBuilder();
    for (int i=0;i<files.size(); i++) {
      UploadedFile file = files.get(i);
      String td1 = "<td><label for=\"file"+file.getFileId()+"\">";
      String td2 = "</label></td>\n";
      sb.append( "<tr class=\""+(i%2==1?"odd":"even")+"\">\n" );
      sb.append( td1+"<input type=\"checkbox\" name=\"fileId\" class=\"fileId\" value=\""+file.getFileId()+"\" id=\"file"+file.getFileId()+"\">"+td2 );
      //sb.append( td1+"<nobr>"+file.getType()+"</nobr>"+td2 );
      sb.append( td1+"<nobr>"+file.getFileName()+"</nobr>"+td2 );
      sb.append( td1+"<nobr>"+file.getDescription()+"</nobr>"+td2 );
      sb.append( td1+"<nobr>"+file.getDate()+"</nobr>"+td2 );
      sb.append( td1+"<nobr>"+FileUtils.byteCountToDisplaySize(file.getSize())+"</nobr>"+td2 );
      // owner
      sb.append( "<td><select name=\"owner-"+file.getFileId()+"\">\n" );
      for ( User u : users ) {
        sb.append( "<option"+(u.getUserId()==file.getUserId()?" selected":"")+" value=\""+u.getUserId()+"\">"+u.getUserName()+"</option>\n");
      }
      sb.append( "</select></td>\n" ); 
      
      // task 
      
      for ( Task t : tasks ) { 
        boolean accessible = false;
        if (file.getPermission()!=null) {
          for (int permittedTaskId : file.getPermission()) {
            if (permittedTaskId==t.getTaskId()) {
              accessible = true;
              break;
            }
          }
        }
        sb.append( "<td><input type=\"checkbox\" value=\"1\""
            +(accessible?" checked":"")+" name=\"permission-"+file.getFileId()+"-"+t.getTaskId()+"\"></td>" );
      }
      
      sb.append( "</tr>\n" );
    }
    return sb.toString();
  }
  
  public String getButton() {
    return "<br><br>"+
    Downloader.getCheckAllButton()+
    "<br>\n"+
    "Actions for the selected items:<br>\n"+
    "<script type=\"text/javascript\">\n"+
    "  function proxy(actionType) {\n" +
    "    if(!verifyChecked('fileId')){\n" +
    "      alert('Please select the files to apply action');\n" +
    "      return false;\n" +
    "    };\n" +
    "    $('actionType').value = actionType;\n" +
    "    document.dl_form.submit(); }\n" +
    "</script>\n"+
    "<input type=\"hidden\" name=\"actionType\" id=\"actionType\">\n"+
    "<input type=\"button\" value=\"Download\" onclick=\"proxy('download')\">&nbsp;&nbsp;\n"+
    "<input type=\"button\" value=\"Update Owner/Visibility\" onclick=\"proxy('update')\">&nbsp;&nbsp;\n"+
    "<input type=\"button\" value=\"Delete\" onclick=\"javascript:if(!deleteConfirmed()){return;}else{proxy('delete');}\">&nbsp;&nbsp;\n";
  }
  
  private String getTableHeader(List<Task> tasks) {
    StringBuilder sb = new StringBuilder();
    sb.append("<tr>\n");
    sb.append("<th rowspan=\"2\" valign=\"bottom\">&nbsp;</th>\n");
    //sb.append("<th rowspan=\"2\" valign=\"bottom\">Type</th>\n");
    sb.append("<th rowspan=\"2\" valign=\"bottom\">Name</th>\n");
    sb.append("<th rowspan=\"2\" valign=\"bottom\">Description</th>\n");
    sb.append("<th rowspan=\"2\" valign=\"bottom\">Date modified</th>\n");
    sb.append("<th rowspan=\"2\" valign=\"bottom\">Size</th>\n");
    sb.append("<th rowspan=\"2\" valign=\"bottom\">Owner</th>\n");
    sb.append("<th colspan=\""+tasks.size()+"\">Visibility to Task Participants</th>\n");
    sb.append("</tr>\n");
    sb.append("<tr>\n");
    for ( Task t : tasks ) {
      sb.append("<th valign=\"bottom\"><script type=\"text/javascript\">printRotatedText(\""+t.getFullName()+"\")</script></th>\n");
    }
    sb.append("</tr>\n");
    return sb.toString();
  }
  
}
